#include "city.h"
#include "cell.h"
#include "building.h"
#include "json.hpp"
#include "loan.h"
#include <iostream>
#include <set>
#include <fstream>
#include <sstream>
#include <random>
using namespace std;
using json = nlohmann::json;

const std::string PURPLE = "\033[35m";

void cursor::up(){ if(y > 0) --y;}
void cursor::down(){ if(y < (limit_y - 1)) ++y; }
void cursor::left(){ if(x > 0) --x; }
void cursor::right(){ if(x < (limit_x - 1)) ++x; }
int cursor::posx() const{ return x; }
int cursor::posy() const{ return y; }
int cursor::limitx() const{ return limit_x; }
int cursor::limity() const{ return limit_y; }
void city::unemploy_cell(int x, int y){
	vector<pair<int, int>> employment_vector = _map[x][y].get_employment_vector();
	vector<pair<int, int>>::iterator begin = employment_vector.begin();

	while(begin != employment_vector.end()){
		_map[(*begin).first][(*begin).second].delete_employment(x,y);
		if(_map[(*begin).first][(*begin).second].get_building().get_type() == RESIDENTIAL)
			_unemployment_vector.push_back(pair<int,int>((*begin).first,(*begin).second));
		
		begin++;
	}

	_map[x][y].clear_employment();
	if(_map[x][y].get_building().get_type() == RESIDENTIAL)
		_unemployment_vector.push_back(pair<int,int>(x,y));
}
void city::employ_cell(int x, int y){

	if(_unemployment_vector.size() > 0 && (_map[x][y].get_building().get_type() == INDUSTRY || _map[x][y].get_building().get_type() == SHOPS)){
		pair<int, int> c2 = _unemployment_vector[0];
		_map[x][y].set_employment(c2.first, c2.second);
		_map[c2.first][c2.second].set_employment(x, y);
		_unemployment_vector.erase(_unemployment_vector.begin());
	}
}
void city::road_traffic(int i, int e){

	vector<pair<int,int>> employment = _map[i][e].get_employment_vector();
	for(size_t x = 0; x < employment.size(); ++x){
		vector<pair<int,int>> route = smaller_route(i, e, employment[x].first, employment[x].second);
		
		for(size_t r = 0; r < route.size(); ++r){
			_map[route[r].first][route[r].second].set_traffic(_map[route[r].first][route[r].second].get_traffic() + 1);
		}
	}
}
/*
 * direction:
 *   0: up
 *   1: right
 *   2: down
 *   3: left
 */
pair<int,int> city::get_near_road(int i, int e){
	int direction = 0;
	int local = _map[i][e].get_access();
	if(e > 0 && _map[i][e - 1].get_access() > local)
		direction = 3;
	else if(i > 0 && _map[i - 1][e].get_access() > local)
		direction = 0;
	else if(e < int(_map[i].size()) && _map[i][e + 1].get_access() > local)
		direction = 1;
	else if(i < int(_map.size()) && _map[i + 1][e].get_access() > local)
		direction = 2;
	switch(direction){
		case 0:{
			int x = i, y = e;
			while(x > 0 && _map[x][y].get_building().get_type() != ROAD){
				--x;
			}
			return make_pair(x,y);
		};break;
		case 1:{
			int x = i, y = e;
			while(y < int(_map[x].size()) && _map[x][y].get_building().get_type() != ROAD){
				++y;
			}
			return make_pair(x,y);
		};break;
		case 2:{
			int x = i, y = e;
			while(x < int(_map.size()) && _map[x][y].get_building().get_type() != ROAD){
				++x;
			}
			return make_pair(x,y);
		};break;
		case 3:{
			int x = i, y = e;
			while(y > 0 && _map[x][y].get_building().get_type() != ROAD){
				--y;
			}
			return make_pair(x,y);
		};break;
	}
	return make_pair(-1,-1);
}

int city::positions_to_node(int i, int e){
	return i * _map.size() + e;
}

void city::pay_bigger_city(){
	int previous_size = _size;
	
	if(_money >= (_size + 1) * 10){
		_size += 1;
		vector<cell> c(_size, cell());
		_money -= _size * 10;
		for(int i = 0; i < previous_size; ++i){
			_map[i].push_back(cell());
		}
		_map.push_back(c);
				
	}
}

pair<int,int> city::node_to_positions(int node) {
	return make_pair(node / _map.size(), node % _map.size());
}

vector<pair<int,int>> city::dijkstra(int x, int y, int dest_x, int dest_y) {
	int max = _map[x].size() * _map.size();
	int n = max;
	int start_node = positions_to_node(x,y);
	int end_node = positions_to_node(dest_x,dest_y);
	int cost[max][max], distance[max], pred[max];
	int visited[max], count, min_distance, next_node = -1, i, j;
	for(i = 0;i < n; i++){
		for(j = 0; j < n ; j++){
			pair<int, int> origin = node_to_positions(i);
			pair<int, int> destination = node_to_positions(j);
			cost[i][j] = int(INFINITY);
			if(i == j)
				cost[i][j] = 0;
			else{
				int z = 0;
				bool near = false;
				if(origin.first + 1 == destination.first)
					--z;
				if(origin.second + 1 == destination.second)
					--z;
				if(origin.first == destination.first){
					near = true;
					++z;
				}
				if(origin.second == destination.second){
					++z;
					near = true;
				}
				if(origin.first -1 == destination.first)
					--z;
				if(origin.second - 1 == destination.second)
					--z;
				if(z == 0 && near && _map[origin.first][origin.second].get_building().get_type() == ROAD && _map[destination.first][destination.second].get_building().get_type() == ROAD){
					cost[i][j] = 1;
				}else{
					cost[i][j] = int(INFINITY);
				}
			}
		}
	}
	for(i = 0; i < n; i++) {
		distance[i] = cost[start_node][i];
		pred[i] = start_node;
		visited[i] = 0;
	}

	pair<int, int> previous_node;
	distance[start_node] = 0;
	visited[start_node] = 1;
	count = 1;
	while(count < n - 1) {
		min_distance = int(INFINITY);
		for(i = 0; i < n; i++) {
			//TODO: Match differences between direction and one way road
			if(i > 0 &&  _map[node_to_positions(i).first][node_to_positions(i).second].get_building().get_type() == ONE_WAY_ROAD) {
				previous_node = node_to_positions(pred[i - 1]);
				pair<int,int> prev_positions = previous_node;
				pair<int,int> next_positions = node_to_positions(i);
				int x = prev_positions.first - next_positions.first;
				int y = prev_positions.second - next_positions.second;

				int direction = _map[node_to_positions(i).first][node_to_positions(i).second].get_direction();
				if( !(x > 0 && direction == 1) || !(x < 0 && direction == 2) || !(y < 0 && direction == 3) || !(y > 0 && direction == 4)){
					distance[i] = int(INFINITY);
				}
			}
			if(distance[i] < min_distance && !visited[i]) {
				min_distance = distance[i];
				next_node = i;
			}
		}
		if(next_node != -1){
			visited[next_node] = 1;
			for(i = 0; i < n; i++)
				if(!visited[i])
					if(min_distance + cost[next_node][i] < distance[i]) {
						distance[i] = min_distance + cost[next_node][i];
						pred[i] = next_node;
					}
		}
		count++;
	}
	vector<pair<int,int>> v;

	if(distance[end_node] != int(INFINITY)){
		int temp_node = end_node;
		pair<int,int> p = node_to_positions(temp_node);
		do {
			temp_node = pred[temp_node];

			p = node_to_positions(temp_node);
			v.push_back(p);
		}while(temp_node != start_node);
	}
	return v;
}

vector<pair<int,int>> city::smaller_route(int origin_x, int origin_y, int destination_x, int destination_y){
	pair<int, int> origin = get_near_road(origin_x, origin_y);
	pair<int, int> destination = get_near_road(destination_x, destination_y);

	return dijkstra(origin.first, origin.second, destination.first, destination.second);
}

city::city(const string& name, int money, int size): _name(name), 
	_money(money), _size(size), _time(32), _population(0), _residentials(0), _shops(0), _industry(0),
	_select(cursor(0, 0, size, size)), _waste(0){

	ifstream in(_name + ".json");
	if(in){
		try{
			load();
		}catch(...){ create(); }
	}else{
		create();
	}
}
void city::print(){
	cout << "\nType------------" << endl;
	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map[i].size(); ++e){
			if(_select.posx() == int(e) && _select.posy() == int(i))
				cout << PURPLE << _map[e][i].get_building().get_type() << " " << _map[e][i].clear_color();
			else
				cout << _map[e][i].color_by_type() <<  _map[e][i].get_building().get_type() << " " << _map[e][i].clear_color();
		}
		cout << endl;
	}
	cout << "Electricity-------" << endl;
	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map[i].size(); ++e){
			if(_select.posx() == int(e) && _select.posy() == int(i))
				cout << PURPLE << _map[e][i].get_electricity() << " " << _map[e][i].clear_color();
			else
				cout << _map[e][i].color_by_electricity() << _map[e][i].get_electricity() << " " << _map[e][i].clear_color();
		}
		cout << endl;
	}
	cout << "Water-------" << endl;
	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map[i].size(); ++e){
			if(_select.posx() == int(e) && _select.posy() == int(i))
				cout << PURPLE << _map[e][i].get_water() <<  " " << _map[e][i].clear_color();
			else
				cout << _map[e][i].color_by_water() << _map[e][i].get_water() << " " << _map[e][i].clear_color();
		}
		cout << endl;
	}
	cout << "Pollution---------" << endl;
	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map[i].size(); ++e){
			if(_select.posx() == int(e) && _select.posy() == int(i))
				cout << PURPLE << _map[e][i].get_air_pollution() << " " << _map[e][i].clear_color();
			else
				cout << _map[e][i].color_by_pollution() << _map[e][i].get_air_pollution() <<  " " << _map[e][i].clear_color();
		}
		cout << endl;
	}
	cout << "Access------------" << endl;
	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map[i].size(); ++e){
			if(_select.posx() == int(e) && _select.posy() == int(i))
				cout << PURPLE << _map[e][i].get_access() << " " << _map[e][i].clear_color();
			else
				cout << _map[e][i].color_by_access() << _map[e][i].get_access() << " " << _map[e][i].clear_color();
		}
		cout << endl;
	}
	cout << "Traffic------------" << endl;
	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map[i].size(); ++e){
			if(_select.posx() == int(e) && _select.posy() == int(i))
				cout << PURPLE << _map[e][i].get_traffic() << " " << _map[e][i].clear_color();
			else
				cout << _map[e][i].color_by_traffic() << _map[e][i].get_traffic() << " " << _map[e][i].clear_color();
		}
		cout << endl;
	}
	cout << "working people------------" << endl;
	int workers = 0;
	int jobs = 0;
	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map[i].size(); ++e){
			for(unsigned z = 0; z < _map[i][e].get_employment_vector().size(); ++z){
				if(_map[i][e].get_building().get_type() == 2)
					++workers;
				else if(_map[i][e].get_building().get_type() != 2)
					++jobs;
				cout << _map[i][e].get_employment_vector()[z].first << " " << _map[i][e].get_employment_vector()[z].second << endl;
			}
		}
	}
	
	cout << "Wind------------" << endl;
	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map[i].size(); ++e){
			if(_select.posx() == int(e) && _select.posy() == int(i))
				cout << PURPLE << _map[e][i].get_wind() << " " << _map[e][i].clear_color();
			else
				cout << _map[e][i].color_by_type() << _map[e][i].get_wind() << " " << _map[e][i].clear_color();
		}
		cout << endl;
	}
	cout << "Building time------------" << endl;
	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map[i].size(); ++e){
			if(_select.posx() == int(e) && _select.posy() == int(i))
				cout << PURPLE << _map[e][i].get_building_time() << " " << _map[e][i].clear_color();
			else
				cout << _map[e][i].color_by_building_time() << _map[e][i].get_building_time() << " " << _map[e][i].clear_color();
		}
		cout << endl;
	}
	cout << "jobs " << jobs << "\nworkers " << workers << endl;
	cout << "unemployment------" << endl;
	for(unsigned i = 0; i < _unemployment_vector.size(); ++i){
		cout << _unemployment_vector[i].first << " " << _unemployment_vector[i].second <<endl;
	}
	cout << "garbage: " << _waste << endl;
}

void city::set_cell(cell c){
	int destroy = 0;
	if(_map[_select.posx()][_select.posy()].get_building().get_type() != LAND){
		cout << "Do you want to destroy the building in that position?" << endl;
		cout << "1.- Yes (it'll cost 100 vakuoj)\n2.- No" << endl;
		_money -= 100;
		cin >> destroy;
	}

	if(destroy == 1 or
		_map[_select.posx()][_select.posy()].get_building().get_type() == LAND){

		_money -= c.get_building().get_cost();
		if(_map[_select.posx()][_select.posy()].get_building().get_type() == INDUSTRY or
			_map[_select.posx()][_select.posy()].get_building().get_type() == RESIDENTIAL or
			_map[_select.posx()][_select.posy()].get_building().get_type() == SHOPS)

			unemploy_cell( _select.posx(),_select.posy());

		_map[_select.posx()][_select.posy()] = c;
		if(c.get_building().get_type() == 2)
			_unemployment_vector.push_back(pair<int,int>(_select.posx(),_select.posy()));

	}
}
void city::set_pipe(){
	_map[_select.posx()][_select.posy()].set_pipe(true);
}

void city::flow_water(int i, int e){
	if(_map[i][e].get_water() > 0 && _map[i][e].has_pipe()){
		for(int o = 3; o > 0; --o){

			if((i - o) >= 0)
				_map[i - o][e].set_water(4 - o);
			if((e - o) >= 0)
				_map[i][e - o].set_water(4 - o);
			if((i + o) < _map[i].size())
				_map[i + o][e].set_water(4 - o);
			if((e + o) < _map[i].size())
				_map[i][e + o].set_water(4 - o);
		}
	}
}
void city::nextGeneration(){
	set_residentials(0);
	set_shops(0);
	set_industry(0);
	set_waste(0);

	_unemployment_vector.clear();
	
	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map.size(); ++e){
			_map[i][e].set_air_pollution(0); //Think better solution
			_map[i][e].set_electricity(0);
			_map[i][e].set_water(0);
			_map[i][e].set_traffic(0);
		}
	}

	vector<vector<cell>> new_field = _map;

	int wind = _wind;
	for(unsigned i = 0;i < _map.size(); ++i){
		
		for(unsigned e = 0;e < _map[i].size(); ++e){
				
			if(_map[i][e].get_building().get_type() == POWER_STATION)
				electricity(i,e);

			if(_map[i][e].get_building().get_type() == WATER_STATION)
				water(i,e);
			
			_map[i][e].set_access(road(i,e));

			ecosystem_pollution(new_field,i,e);

			//Count buildings
			if(_map[i][e].get_building().get_type() == RESIDENTIAL)
				++_residentials;
			else if(_map[i][e].get_building().get_type() == INDUSTRY)
				++_industry;
			else if(_map[i][e].get_building().get_type() == SHOPS)
				++_shops;
			
			if(_map[i][e].get_building().get_type() == GARBAGE_INCINERATOR)
				_waste -= _map[i][e].get_building().get_waste();
			else
				_waste += _map[i][e].get_building().get_waste();

		}
	}

	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map[i].size(); ++e){
			if(_map[i][e].get_building().get_type() == RESIDENTIAL && _map[i][e].get_employment_vector().size() < 1
				&& _map[i][e].has_needs_met())
				_unemployment_vector.push_back(pair<int,int>(i,e));

			if(_map[i][e].get_building().get_type() == RESIDENTIAL){
				set_residentials(get_residentials() + 1);

			}
			if((_map[i][e].get_building().get_type() == SHOPS ||
				_map[i][e].get_building().get_type() == RESIDENTIAL ||
				_map[i][e].get_building().get_type() == INDUSTRY)
				&& int(_map[i][e].get_employment_vector().size()) < _map[i][e].get_building().get_max_people()){

				employ_cell(i,e);
				if(_map[i][e].get_building().get_type() == RESIDENTIAL)
					road_traffic(i,e);
			}
			_map[i][e].set_air_pollution(
				new_field[i][e].get_air_pollution());
			set_population(get_population() + population(i,e));
			if(_map[i][e].has_pipe())
				flow_water(i,e);
				
			if(_map[i][e].get_building_time() > 0)
				_map[i][e].set_building_time(_map[i][e].get_building_time() - 1);
		}
	}
}
void city::electricity(int i, int e){
	if(_map[i][e].get_building().get_type() == POWER_STATION){
		vector<cursor> vector_cell;
		
		cursor _cursor(i, e, _map.size(), _map[i].size());
		vector_cell.push_back(_cursor);
		int electricity = 0;

		while(vector_cell.size() > 0 && electricity >= 0){

			cursor _last_cursor(vector_cell[0]);
			if(_map[_last_cursor.posx()][_last_cursor.posy()].get_electricity() == 0){
				if(_map[_last_cursor.posx()][_last_cursor.posy()].get_building().get_type() !=
					LAND){

					if(_map[_last_cursor.posx()][_last_cursor.posy()].get_building().get_type() ==
						POWER_STATION && _map[_last_cursor.posx()][_last_cursor.posy()].get_electricity()
						!= -1){
						
						if(_map[_last_cursor.posx()][_last_cursor.posy()].get_access() > 0){
							_map[_last_cursor.posx()][_last_cursor.posy()].set_electricity(-1);
							electricity += _map[_last_cursor.posx()][_last_cursor.posy()]
								.get_building().get_electricity_consumption();
						}
						if(_last_cursor.posx() < _last_cursor.limitx() - 1){
							cursor c = _last_cursor;
							c.right();
							if(_map[c.posx()][c.posy()].get_electricity() == 0)
								insertion_not_repeated(c, vector_cell);
								
						}
						if(_last_cursor.posy() < _last_cursor.limity() - 1){
							cursor c = _last_cursor;
							c.down();
							if(_map[c.posx()][c.posy()].get_electricity() == 0)
								insertion_not_repeated(c, vector_cell);
						}

						if(_last_cursor.posy() > 0){
							cursor c = _last_cursor;
							c.up();
							if(_map[c.posx()][c.posy()].get_electricity() == 0)
								insertion_not_repeated(c, vector_cell);
						}
						if(_last_cursor.posx() > 0){
							cursor c = _last_cursor;
							c.left();
							if(_map[c.posx()][c.posy()].get_electricity() == 0)
								insertion_not_repeated(c, vector_cell);
						}
					}else{
						if(electricity >= _map[_last_cursor.posx()][_last_cursor.posy()]
							.get_building().get_electricity_consumption()){

							electricity -= _map[_last_cursor.posx()][_last_cursor.posy()]
								.get_building().get_electricity_consumption();

							_map[_last_cursor.posx()][_last_cursor.posy()]
								.set_electricity(electricity);


							if(_last_cursor.posx() < _last_cursor.limitx() - 1){
								cursor c = _last_cursor;
								c.right();
								if(_map[c.posx()][c.posy()].get_electricity() == 0)
									insertion_not_repeated(c, vector_cell);
									
							}
							if(_last_cursor.posy() < _last_cursor.limity() - 1){
								cursor c = _last_cursor;
								c.down();
								if(_map[c.posx()][c.posy()].get_electricity() == 0)
									insertion_not_repeated(c, vector_cell);
							}

							if(_last_cursor.posy() > 0){
								cursor c = _last_cursor;
								c.up();
								if(_map[c.posx()][c.posy()].get_electricity() == 0)
									insertion_not_repeated(c, vector_cell);
							}
							if(_last_cursor.posx() > 0){
								cursor c = _last_cursor;
								c.left();
								if(_map[c.posx()][c.posy()].get_electricity() == 0)
									insertion_not_repeated(c, vector_cell);
							}
						}
					}
					
				}
			}
			vector<cursor>::iterator it = vector_cell.begin();
			vector_cell.erase(it);

			if(electricity <= 0)
				electricity = -1;

		}
	}
}

void city::insertion_not_repeated(cursor c, vector<cursor>& v){
	bool inserted = false;
	for(size_t i = 0; i < v.size(); ++i)
		if(v[i].posy() == c.posy() && v[i].posx() == c.posx())
			inserted = true;
	if(!inserted)
		v.push_back(c);
}
void city::water(int i, int e){
	if(_map[i][e].get_building().get_type() == WATER_STATION){
		vector<cursor> vector_cell;

		cursor _cursor(i, e, _map.size(), _map[i].size());
		vector_cell.push_back(_cursor);
		int water = 0;
		while(vector_cell.size() > 0 && water >= 0){

			cursor _last_cursor(vector_cell[0]);
			if(_map[_last_cursor.posx()][_last_cursor.posy()].get_water() == 0){
				if(_map[_last_cursor.posx()][_last_cursor.posy()].get_building().get_type() != LAND){

					if(_map[_last_cursor.posx()][_last_cursor.posy()].get_building().get_type() == WATER_STATION
						 && _map[_last_cursor.posx()][_last_cursor.posy()].get_water() != -1){
						
						if(_map[_last_cursor.posx()][_last_cursor.posy()].get_access() > 0){
							_map[_last_cursor.posx()][_last_cursor.posy()].set_water(-1);
							water += _map[_last_cursor.posx()][_last_cursor.posy()]
								.get_building().get_water_consumption();
						}
						if(_last_cursor.posx() < _last_cursor.limitx() - 1){
							cursor c = _last_cursor;
							c.right();
							if(_map[c.posx()][c.posy()].get_water() == 0)
								vector_cell.push_back(c);
						}
						if(_last_cursor.posy() < _last_cursor.limity() - 1){
							cursor c = _last_cursor;
							c.down();
							if(_map[c.posx()][c.posy()].get_water() == 0)
								vector_cell.push_back(c);
						}

						if(_last_cursor.posy() > 0){
							cursor c = _last_cursor;
							c.up();
							if(_map[c.posx()][c.posy()].get_water() == 0)
								vector_cell.push_back(c);
						}
						if(_last_cursor.posx() > 0){
							cursor c = _last_cursor;
							c.left();
							if(_map[c.posx()][c.posy()].get_water() == 0)
								vector_cell.push_back(c);
						}
					}else{
						if(water >= _map[_last_cursor.posx()][_last_cursor.posy()]
							.get_building().get_water_consumption() &&  _map[_last_cursor.posx()][_last_cursor.posy()].has_pipe()){

							water -= _map[_last_cursor.posx()][_last_cursor.posy()]
								.get_building().get_water_consumption();

							_map[_last_cursor.posx()][_last_cursor.posy()]
								.set_water(water);
							if(_last_cursor.posx() < _last_cursor.limitx() - 1){
								cursor c = _last_cursor;
								c.right();
								if(_map[c.posx()][c.posy()].get_water() == 0)
									vector_cell.push_back(c);
							}
							if(_last_cursor.posy() < _last_cursor.limity() - 1){
								cursor c = _last_cursor;
								c.down();
								if(_map[c.posx()][c.posy()].get_water() == 0)
									vector_cell.push_back(c);
							}

							if(_last_cursor.posy() > 0){
								cursor c = _last_cursor;
								c.up();
								if(_map[c.posx()][c.posy()].get_water() == 0)
									vector_cell.push_back(c);
							}
							if(_last_cursor.posx() > 0){
								cursor c = _last_cursor;
								c.left();
								if(_map[c.posx()][c.posy()].get_water() == 0)
									vector_cell.push_back(c);
							}
						}
					}
				}
			}
			vector<cursor>::iterator it = vector_cell.begin();
			vector_cell.erase(it);

			if(water <= 0)
				water = -1;

		}
	}
}

void city::save(){
	json j;

	nlohmann::json map_tile;
	for(int i = 0; i < _size; ++i){
		stringstream ss;
		ss << i;
		vector<int> sf;
		nlohmann::json row;

		for(int e = 0; e < _size; ++e){
			row.push_back(_map[i][e].get_building().get_type());
		}
		map_tile.push_back(row);
	}
	j["map-tile"] = map_tile;
	nlohmann::json map_wind;
	for(int i = 0; i < _size; ++i){
		stringstream ss;
		ss << i;
		vector<int> sf;
		nlohmann::json row;

		for(int e = 0; e < _size; ++e){
			row.push_back(_map[i][e].get_wind());
		}
		map_wind.push_back(row);
	}
	j["map-wind"] = map_wind;
	
	nlohmann::json map_building_time;
	for(int i = 0; i < _size; ++i){
		stringstream ss;
		ss << i;
		vector<double> sf;
		nlohmann::json row;

		for(int e = 0; e < _size; ++e){
			row.push_back(_map[i][e].get_building_time());
		}
		map_building_time.push_back(row);
	}
	j["map-building-time"] = map_building_time;
	
	
	j["money"] = _money;
	j["time"] = _time;
	j["size"] = _size;
	j["population"] = _population;
	j["loans"] = _possible_loans.size();
	for(unsigned e = 0; e < _possible_loans.size(); ++e){
		stringstream ss;
		ss << e;
		j["possible-loan" + ss.str() + "-description"] = _possible_loans[e].get_description();
		j["possible-loan" + ss.str() + "-money"] = _possible_loans[e].get_money();
		j["possible-loan" + ss.str() + "-months"] = _possible_loans[e].get_months();
		j["possible-loan" + ss.str() + "-installment"] = _possible_loans[e].get_installment();
	}
	j["asked-loans"] = _asked_out_loans.size();

	for(unsigned e = 0; e < _asked_out_loans.size(); ++e){
		stringstream ss;
		ss << e;
		j["asked-loan" + ss.str() + "-description"] = _asked_out_loans[e].get_description();
		j["asked-loan" + ss.str() + "-money"] = _asked_out_loans[e].get_money();
		j["asked-loan" + ss.str() + "-months"] = _asked_out_loans[e].get_months();
		j["asked-loan" + ss.str() + "-installment"] = _asked_out_loans[e].get_installment();
	}

	std::ofstream out(_name + ".json");
	out << j.dump() << endl;
	out.close();
}

void city::create(){
	random_device rd;
	default_random_engine eng(rd());
	uniform_int_distribution<int> wind_value_distr(0, 20);
	_wind = wind_value_distr(eng);
	
	uniform_int_distribution<int> wind_variation_distr(-1, 1);
	
	int wind = _wind;
	for(int i = 0; i < _size; ++i){
		_map.push_back(vector<cell>());
		for(int e = 0; e < _size; ++e){
			_map[i].push_back(cell());
			if(i)
				wind = _map[i - 1][e].get_wind();
			_map[i][e].set_wind(wind + wind_variation_distr(eng));
			_map[i][e].set_building_time(0);
		}
	}
	_buildings = load_buildings();
	_possible_loans.push_back(loan("Good loan", 10000, 12, 10000));
}

void city::load(){
	std::ifstream in(_name + ".json");
	if(in){
		json j = json::parse(in);
		_map = vector<vector<cell>>();
		_size = j.at("map-tile").size();
		_select = cursor(_select.posx(), _select.posy(), _size, _size);
		_buildings = load_buildings();
		for(int i = 0; i < _size; ++i){

			vector<int> sf;
			j.at("map-tile").at(i).get_to(sf);
			vector<cell> vc;
			for(int e = 0; e < _size; ++e){
				vc.push_back( cell(_buildings[sf[e]]) );
				if(sf[e] == 2)
					_unemployment_vector.push_back(pair<int,int>(i,e));
			}
			_map.push_back(vc);
		}
		
		for(int i = 0; i < _size; ++i){

			vector<int> sf;
			j.at("map-wind").at(i).get_to(sf);
			vector<cell> vc;
			for(int e = 0; e < _size; ++e){
				_map[i][e].set_wind(sf[e]);
			}

		}
		
		for(int i = 0; i < _size; ++i){

			vector<double> bt;
			j.at("map-building-time").at(i).get_to(bt);
			vector<cell> vc;
			for(int e = 0; e < _size; ++e){
				_map[i][e].set_building_time(bt[e]);
			}

		}
		in.close();
		_possible_loans.clear();
		for(unsigned e = 0; e < j.at("loans"); ++e){
			stringstream ss;
			ss << e;

			loan n(j.at("possible-loan" + ss.str() + "-description"),
				j.at("possible-loan" + ss.str() + "-money"),
				j.at("possible-loan" + ss.str() + "-months"),
				j.at("possible-loan" + ss.str() + "-installment"));
			_possible_loans.push_back(n);
			
		}
		for(unsigned e = 0; e < j.at("asked-loans"); ++e){
			stringstream ss;
			ss << e;
			loan n(j.at("asked-loan" + ss.str() + "-description"),
				j.at("asked-loan" + ss.str() + "-money"),
				j.at("asked-loan" + ss.str() + "-months"),
				j.at("asked-loan" + ss.str() + "-installment"));
			_asked_out_loans.push_back(n);
		}
		j.at("money").get_to(_money);
		j.at("time").get_to(_time);
		j.at("size").get_to(_size);
		
		j.at("population").get_to(_population);
	}
}

void city::ecosystem_pollution(vector<vector<cell>>& new_field, int i, int e){
	int base_pollution = _map[i][e].get_building().get_air_pollution();
	int top_limit = i + base_pollution + 1;
	int bottom_limit = i - base_pollution - 1;
	int left_limit = e - base_pollution - 1;
	int right_limit = e + base_pollution + 1;
	int size = _map.size() - 1;
	
	if(bottom_limit < 0)
		bottom_limit = 0;
	if(left_limit < 0)
		left_limit = 0;
	if(right_limit >= size)
		right_limit = size;
	if(top_limit >= size)
		top_limit = size;

	if(base_pollution > 1){
		for(int y = bottom_limit; y <= top_limit; ++y){
			for(int x = left_limit; x <= right_limit; ++x){
				int calculated_pollution = base_pollution - (abs(y - i) + abs(x - e));
				if(calculated_pollution > 0)
		  			new_field[y][x].set_air_pollution(
						new_field[y][x].get_air_pollution() + calculated_pollution
						);

			}
		}
	}else
		new_field[i][e].set_air_pollution(
			new_field[i][e].get_air_pollution() + base_pollution);

}
int city::population(int i, int e){
	if(_map[i][e].get_building().get_type() == RESIDENTIAL and 
		_map[i][e].get_electricity() > 0 and _map[i][e].get_access() > 0)
	  return _buildings[RESIDENTIAL].get_max_people();
	else
	  return 0;
}

int city::road(int i, int e){
	int result = 0;
	int size = _map.size() - 1;
	switch(_map[i][e].get_building().get_type()){
		case LAND:{
			result = 0;
		};break;
		case ROAD:{
			result = 4;
		};break;
		case RESIDENTIAL:{
			if(i != size and _map[i+1][e].get_access() != 0)
				result = _map[i+1][e].get_access() - 1;
			
			if(e != size and _map[i][e+1].get_access() > result)
				result = _map[i][e+1].get_access() - 1;
			
			if(i != 0 and _map[i-1][e].get_access() > result)
				result = _map[i-1][e].get_access() - 1;
			
			if(e != 0 and _map[i][e-1].get_access() > result)
				result = _map[i][e-1].get_access() - 1;
			
		};break;
		case POWER_STATION:{
			if(i != size and _map[i+1][e].get_access() != 0)
				result = _map[i+1][e].get_access() - 1;

			if(e != size and _map[i][e+1].get_access() > result)
				result = _map[i][e+1].get_access() - 1;

			if(i != 0 and _map[i-1][e].get_access() > result)
				result = _map[i-1][e].get_access() - 1;

			if(e != 0 and _map[i][e-1].get_access() > result)
				result = _map[i][e-1].get_access() - 1;

		};break;
		case SHOPS:{
			if(i != size and _map[i+1][e].get_access() != 0)
				result = _map[i+1][e].get_access() - 1;

			if(e != size and _map[i][e+1].get_access() > result)
				result = _map[i][e+1].get_access() - 1;

			if(i != 0 and _map[i-1][e].get_access() > result)
				result = _map[i-1][e].get_access() - 1;

			if(e != 0 and _map[i][e-1].get_access() > result)
				result = _map[i][e-1].get_access() - 1;

		};break;
		case INDUSTRY:{
			if(i != size and _map[i+1][e].get_access() != 0)
				result = _map[i+1][e].get_access() - 1;

			if(e != size and _map[i][e+1].get_access() > result)
				result = _map[i][e+1].get_access() - 1;

			if(i != 0 and _map[i-1][e].get_access() > result)
				result = _map[i-1][e].get_access() - 1;

			if(e != 0 and _map[i][e-1].get_access() > result)
				result = _map[i][e-1].get_access() - 1;

		};break;
		case WATER_STATION:{
			if(i != size and _map[i+1][e].get_access() != 0)
				result = _map[i+1][e].get_access() - 1;

			if(e != size and _map[i][e+1].get_access() > result)
				result = _map[i][e+1].get_access() - 1;

			if(i != 0 and _map[i-1][e].get_access() > result)
				result = _map[i-1][e].get_access() - 1;

			if(e != 0 and _map[i][e-1].get_access() > result)
				result = _map[i][e-1].get_access() - 1;

		};break;
		default: result = 0;break;
	}
	return result;
}

int city::income(){
	int result = 0;
	int road_costs = 0;
	int electricity_production_costs = 0;
	float loans_debt = 0;
	for(unsigned i = 0; i < _map.size(); ++i){
		for(unsigned e = 0; e < _map[i].size(); ++e){
			if(_map[i][e].get_building().get_type() == RESIDENTIAL and
				_map[i][e].get_electricity() > 0 and _map[i][e].get_access() > 0)

				result += 2;

			else if(_map[i][e].get_building().get_type() == ROAD)
				road_costs += 1;

			else if(_map[i][e].get_building().get_type() == POWER_STATION)
				electricity_production_costs += 5;
		}
	}
	for(unsigned i = 0; i < _asked_out_loans.size(); ++i){
		loans_debt += _asked_out_loans[i].get_installment();
		_asked_out_loans[i].set_months(_asked_out_loans[i].get_months() - 1);
		_asked_out_loans[i].set_money(_asked_out_loans[i].get_money() - _asked_out_loans[i].get_installment());
		if(_asked_out_loans[i].get_months() == 0)
			_asked_out_loans.erase(_asked_out_loans.begin() + i);
	}
	cout << "-------------------" << endl;
	cout << "Monthly review" << endl;
	cout << "Income: " << result << endl;
	cout << "Electricity production costs: " << electricity_production_costs << endl;
	cout << "Road costs: " << road_costs << endl;
	if(_asked_out_loans.size() > 0)
		cout << "Loans installment: " << loans_debt << endl;
	cout << "-------------------" << endl;
	result -= road_costs + electricity_production_costs;
	return result;
}

int city::get_needed_residentials(){
	float sum = (2/3.0) * _industry + (1/3.0) * _shops;
	return (int) sum;
}
int city::get_needed_industry(){
	float sum = 3 * _industry -  _shops;
	sum = sum / 2;
	return (int) sum;
}
int city::get_needed_shops(){
	float sum = 3 * _residentials - 2 * _industry;
	return (int) sum;
}

void city::get_loan(){
	unsigned e;
	for(unsigned i = 0; i < _possible_loans.size(); ++i){
		cout << "loan " << i <<endl;
		cout << "description " << _possible_loans[i].get_description() << endl;
		cout << "money " << _possible_loans[i].get_money() << endl;
		cout << "months " << _possible_loans[i].get_months() << endl;
		cout << "installment " << _possible_loans[i].get_installment() << endl;
		cout << "--------------------------------------" << endl;
	}
	cout << "loan number" << endl;
	cin >> e;
	if(e < _possible_loans.size()){
		_money += _possible_loans[e].get_money();
		_asked_out_loans.push_back(_possible_loans[e]);
		_possible_loans.erase(_possible_loans.begin() + e);
	}
}
